package cn.edu.suda.ada.database.annotation;

import cn.edu.suda.ada.common.utils.StringUtils;
import cn.edu.suda.ada.database.bean.Bean;
import cn.edu.suda.ada.database.exception.DatabaseException;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 数据表工具类
 * <P>
 * 实现 <code>Map</code> 与 <code>Bean Object</code> 的相互转化，以便于数据的操作。
 * 
 * @author JiangJun
 * 
 */
public class BeanUtils {
	/**
	 * 根据表结构数据获得持久化类对象
	 * 
	 * @param beanClass
	 *            持久化类
	 * @param map
	 *            表结构数据
	 * @return 持久化类对象
	 * @throws DatabaseException
	 *             转换时发生异常
	 */
	public static Bean getBean(Class<? extends Bean> beanClass,
			Map<String, Object> map) throws DatabaseException {
		Field[] fields = beanClass.getDeclaredFields();

		Bean bean = null;
		try {
			bean = beanClass.newInstance();
		} catch (Exception e) {
			throw new DatabaseException("无法实例化持久化类！", e);
		}

		for (Field field : fields) {
			String methodName = "set"
					+ StringUtils.firstCharToUpperCase(field.getName());
			Object value = null;
			Class<?> type = field.getType();
			if (field.isAnnotationPresent(FieldMapping.class)) {
				FieldMapping fieldMapping = field
						.getAnnotation(FieldMapping.class);
				value = map.get(fieldMapping.value().toUpperCase());
			} else {
				value = map.get(field.getName().toUpperCase()).toString();
			}
			Method method;
			try {
				method = beanClass.getDeclaredMethod(methodName, type);
				// 仅对存在值的内容进行赋值
				if (value != null) {
					method.invoke(bean, toTypeValue(type, value.toString()));
				}
			} catch (Exception e) {
				throw new DatabaseException("无法获取持久化类的方法！", e);
			}
		}
		return bean;
	}

	/**
	 * 根据字段类型转换字符串
	 * 
	 * @param type
	 *            字段类型
	 * @param value
	 *            字符串值
	 * @return
	 */
	private static Object toTypeValue(Class<?> type, String value) {
		if (String.class == type)
			return value;
		if (Boolean.class == type || boolean.class == type)
			return Boolean.parseBoolean(value);
		if (Byte.class == type || byte.class == type)
			return Byte.parseByte(value);
		if (Short.class == type)
			return Short.parseShort(value);
		if (Integer.class == type || int.class == type)
			return Integer.parseInt(value);
		if (Long.class == type || long.class == type)
			return Long.parseLong(value);
		if (Float.class == type || float.class == type)
			return Float.parseFloat(value);
		if (Double.class == type || double.class == type)
			return Double.parseDouble(value);
		return value;
	}

	/**
	 * 根据持久化类对象获得表结构数据
	 * 
	 * @param beanObject
	 *            持久化对象
	 * @return map结构数据
	 * @throws DatabaseException
	 *             转换时发生异常
	 */
	public static Map<String, Object> getMap(Bean beanObject)
			throws DatabaseException {
		Map<String, Object> data = new HashMap<String, Object>();
		Class<?> c = beanObject.getClass();
		Field[] fields = c.getDeclaredFields();
		for (Field field : fields) {
			String methodName = "get"
					+ StringUtils.firstCharToUpperCase(field.getName());
			String fieldName = null;
			if (field.isAnnotationPresent(FieldMapping.class)) {
				FieldMapping fieldMapping = field
						.getAnnotation(FieldMapping.class);
				fieldName = fieldMapping.value().toUpperCase();
			} else {
				// 会有一个指向外部类的指针this$0
				fieldName = field.getName();
			}
			Method method;
			try {
				method = c.getDeclaredMethod(methodName);
				String value = method.invoke(beanObject) == null ? null
						: String.valueOf(method.invoke(beanObject));
				data.put(fieldName, value);
			} catch (Exception e) {
				throw new DatabaseException("无法获取持久化类的方法！", e);
			}
		}
		return data;
	}
}